package com.aiolos.myioc;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 自定义IOC容器的功能
 * 1、实例化Bean
 * 2、保存Bean
 * 3、提供Bean
 * 4、每一个Bean要产生一个唯一的id与之对应
 */
public class MyIocContainer {

    //2、保存Bean。出于线程安全考虑，使用ConcurrentHashMap
    private Map<String,Object> beans = new ConcurrentHashMap<>();

    /**
     * 1、实例化Bean。
     * 作用：委托Ioc容器创建一个bean
     * @param clazz  要创建的bean的class
     * @param beanId BeanId
     * @param paramBeanIds 要创建的bean的class的构造方法所需要的参数的beanId们
     */
    public void setBeans(Class<?> clazz, String beanId,String... paramBeanIds){
        //1. 组装构造方法所需的参数值
        Object[] paramValues = new Object[paramBeanIds.length];
        for (int i = 0; i < paramBeanIds.length; i++) {
            //约定3：被依赖的Bean需要优先创建
            paramValues[i] = beans.get(paramBeanIds[i]);
        }
        //2. 调用构造方法实例化bean
        Object bean = null;
        for (Constructor<?> constructor : clazz.getConstructors()){
            try {
                bean = constructor.newInstance(paramValues);
                //不处理所有异常，如果没有实例化则bean一定为null
            } catch (InstantiationException e) {
            } catch (IllegalAccessException e) {
            } catch (InvocationTargetException e) {
            }
        }

        if(bean == null){
            //实例化失败，强制报错
            throw new RuntimeException("找不到合适的构造方法实例化bean");
        }
        //3. 将实例化的bean放入beans
        beans.put(beanId, bean);
    }

    /**
     * 3、提供Bean。因为每一个Bean要产生一个唯一的id与之对应，所以通过beanId获取Bean
     * 作用：根据beanId获取一个bean
     * @param beanId
     * @return 返回bean
     */
    public Object getBean(String beanId){
        return beans.get(beanId);
    }
}
